﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Media;
using System.Windows.Forms;
using CloudShot.Controls;
using CloudShot.Core.Interfaces;
using CloudShot.Editor;
using CloudShot.Editor.CanvasFigures;
using CloudShot.Editor.Tools;
using CloudShot.Entities;
using CloudShot.Interfaces;
using CloudShot.Logic;
using CloudShot.Properties;
using CloudShot.Services;
using CloudShot.Settings;
using CloudShot.Utils;
using CloudShot.Utils.Tweens;
using CloudShot.ViewModels;

namespace CloudShot.Forms
{
  internal partial class CaptureForm : Form
  {
    private readonly INotificationService _notificationService;
    private readonly bool _isInstantShot;
    private readonly bool _isSoundsEnabled;
    private readonly object _figureMarker = new object();
    private readonly IConfigurationSection _appConfigurationSection;

    private readonly IFormHotkeyService _canvasHotKeyService = new FormHotkeyService();
    private readonly IFormHotkeyService _propHotkeyService = new FormHotkeyService();
    private readonly IClipboardService _clipboardService = new ClipboardService();

    private readonly Dictionary<RadioButton, Tool> _buttonsToToolsMap = new Dictionary<RadioButton, Tool>();

    private readonly Section _changeToolsSection = new Section();
    private readonly Section _pointerSection = new Section();
    private readonly Section _createCropSection = new Section();
    private readonly Section _resetToolSection = new Section();

    private readonly Animator _animator;
    private TextTool _textTool;

    private PropertiesForm _propertiesForm;

    private Rectangle? _previousCropRectangle;
    private bool _isMouseDown;
    private Tool _activeTool;
    private bool _isTextEditState;

    public override Image BackgroundImage
    {
      get { return canvasControl.BackgroundImage; }
      set { canvasControl.BackgroundImage = value; }
    }

    public CaptureResult CaptureResult { get; private set; }

    private Tool ActiveTool
    {
      get { return _activeTool; }
      set
      {
        if (_activeTool != null)
          _activeTool.Leave();

        _activeTool = value;

        if (_activeTool != null)
        {
          _activeTool.Enter();
          canvasControl.Cursor = _activeTool.Cursor;
        }
      }
    }

    public CaptureForm(StorageContainer storageContainer, IConfigurationSection appConfigurationSection, INotificationService notificationService, Color fillColor, bool isInstantShot, bool isSoundsEnabled)
    {
      _notificationService = notificationService;
      _isInstantShot = isInstantShot;
      _isSoundsEnabled = isSoundsEnabled;

      _appConfigurationSection = appConfigurationSection;

      InitializeComponent();
      canvasControl.FillColor = fillColor;

      var settings = _appConfigurationSection.GetOrCreateAs<CloudShotSettings>();
      canvasControl.ShowEditorHints = !settings.IsHintsDisabled;

      RegisterCanvasHotkeys(_canvasHotKeyService);
      RegisterCanvasHotkeys(_propHotkeyService);

      //main menu
      saveMenu.ShortcutKeyDisplayString = AppHotKeys.SaveImage.ToString();
      copyMenu.ShortcutKeyDisplayString = AppHotKeys.CopyImage.ToString();
      uploadMenu.ShortcutKeyDisplayString = AppHotKeys.UploadImage.ToString();
      cancelMenu.ShortcutKeyDisplayString = AppHotKeys.Cancel.ToString();
      toggleFullscreenMenu.ShortcutKeyDisplayString = AppHotKeys.ToggleFullscreen.ToString();
      deleteAllMenu.ShortcutKeyDisplayString = AppHotKeys.DeleteAllFigures.ToString();
      selectAllMenu.ShortcutKeyDisplayString = AppHotKeys.SelectAll.ToString();

      //figure menu
      duplicateMenu.ShortcutKeyDisplayString = AppHotKeys.DuplicateFigure.ToString();
      deleteMenu.ShortcutKeyDisplayString = AppHotKeys.DeleteFigure.ToString();

      SetTooltipText(saveButton, Resources.Shared_Save, AppHotKeys.SaveImage);
      SetTooltipText(copyButton, Resources.Shared_CopyImage, AppHotKeys.CopyImage);
      SetTooltipText(uploadButton, Resources.Shared_Upload, AppHotKeys.UploadImage);
      SetTooltipText(cancelButton, Resources.Shared_Cancel, AppHotKeys.Cancel);

      uploadButton.SetStorageContainer(storageContainer);

      _animator = new Animator(canvasControl);

      ////TODO: temporary code, if we determine applay this future, code should be refactored!!!
      //float alpha = 0.1f;
      //var opacityTimer = new Timer();
      //opacityTimer.Interval = 10;
      //Opacity = alpha;
      //opacityTimer.Enabled = true;
      //opacityTimer.Tick += (s, a) =>
      //{
      //  alpha += 0.2f;
      //  Opacity = alpha;

      //  if (alpha >= 1f)
      //  {
      //    opacityTimer.Enabled = false;
      //  }
      //};
    }

    private static int CalculatePosition(int toolbarSize, int screenPosition, int screenSize, int cropPosition, int cropSize, int offset)
    {
      int toolbarSizeWithOfset = toolbarSize + offset;
      int cropRectRight = cropPosition + cropSize;

      //into the crop object
      if (cropSize + toolbarSizeWithOfset > screenSize)
        return cropRectRight - toolbarSizeWithOfset;

      //regular location
      if (cropRectRight - screenPosition + toolbarSizeWithOfset <= screenSize)
        return cropRectRight + offset;

      //show on another side
      return cropPosition - toolbarSizeWithOfset;
    }

    private void PlayShotSound()
    {
      if (!_isSoundsEnabled)
        return;

      using (var player = new SoundPlayer(Resources.CAMERA))
      {
        player.Play();
      }
    }

    private void SetTooltipText(Control item, string text, Hotkey hotkey)
    {
      toolTipControl.SetToolTip(item, string.Format("{0} ({1})", text, hotkey));
    }

    private void RegisterCanvasHotkeys(IFormHotkeyService service)
    {
      AddHotKeyToButton(service, frameToolButton, Resources.CaptureForm_FrameTool, AppHotKeys.FrameTool, _changeToolsSection);
      AddHotKeyToButton(service, rectangleToolButton, Resources.CaptureForm_RectangleTool, AppHotKeys.RectangleTool, _changeToolsSection);
      AddHotKeyToButton(service, arrowToolButton, Resources.CaptureForm_ArrowTool, AppHotKeys.ArrowTool, _changeToolsSection);
      AddHotKeyToButton(service, lineToolButton, Resources.CaptureForm_LineTool, AppHotKeys.LineTool, _changeToolsSection);
      AddHotKeyToButton(service, textToolButton, Resources.CaptureForm_TextTool, AppHotKeys.TextTool, _changeToolsSection);
      AddHotKeyToButton(service, pointerToolButton, Resources.CaptureForm_SelectionTool, AppHotKeys.PointerTool, _changeToolsSection);
      AddHotKeyToButton(service, ellipseToolButton, Resources.CaptureForm_EllipseTool, AppHotKeys.EllipseTool, _changeToolsSection);

      service.RegisterHotkey(AppHotKeys.DeleteFigure, OnDeleteFigureClick, _pointerSection);
      service.RegisterHotkey(AppHotKeys.DeleteAllFigures, OnDeleteAllClick, _pointerSection);
      service.RegisterHotkey(AppHotKeys.DuplicateFigure, OnDuplicateFigureClick, _pointerSection);
      service.RegisterHotkey(AppHotKeys.ToggleFullscreen, OnToggleFullscreenClicked); //TODO think about section
      service.RegisterHotkey(AppHotKeys.SelectAll, OnSelectAllClick, _pointerSection);
      service.RegisterHotkey(AppHotKeys.StartEditText, StartEditSelectedCanvasText);

      service.RegisterHotkey(AppHotKeys.MoveSelectionDown, () => MoveSelection(0, 1), _pointerSection);
      service.RegisterHotkey(AppHotKeys.MoveSelectionUp, () => MoveSelection(0, -1), _pointerSection);
      service.RegisterHotkey(AppHotKeys.MoveSelectionLeft, () => MoveSelection(-1, 0), _pointerSection);
      service.RegisterHotkey(AppHotKeys.MoveSelectionRight, () => MoveSelection(1, 0), _pointerSection);

      service.RegisterHotkey(AppHotKeys.MoveSelectionDownLong, () => MoveSelection(0, 50), _pointerSection);
      service.RegisterHotkey(AppHotKeys.MoveSelectionUpLong, () => MoveSelection(0, -50), _pointerSection);
      service.RegisterHotkey(AppHotKeys.MoveSelectionLeftLong, () => MoveSelection(-50, 0), _pointerSection);
      service.RegisterHotkey(AppHotKeys.MoveSelectionRightLong, () => MoveSelection(50, 0), _pointerSection);

      service.RegisterHotkey(AppHotKeys.CopyImage, OnCopyClick, _pointerSection);
      service.RegisterHotkey(AppHotKeys.SaveImage, OnSaveClick, _pointerSection);
      service.RegisterHotkey(AppHotKeys.UploadImage, OnUploadClick, _pointerSection);
      service.RegisterHotkey(AppHotKeys.Cancel, Cancel, _pointerSection);

      service.RegisterHotkey(AppHotKeys.Cancel, Cancel, _createCropSection);
      service.RegisterHotkey(AppHotKeys.Cancel, ResetTool, _resetToolSection);
    }

    private void MoveSelection(int x, int y)
    {
      canvasControl.MoveSelection(new Point(x, y));
    }

    private void AddHotKeyToButton(IFormHotkeyService service, RadioButton btn, string text, Hotkey hotkey, Section section)
    {
      service.RegisterHotkey(hotkey, () => SetActiveToolByButton(btn), section);
      SetTooltipText(btn, text, hotkey);
    }

    //TODO: refactor, very hacking code
    private void FillFiguresContextMenu(List<CanvasObject> objectsBehindCursor)
    {
      List<CanvasObject> preselectedFigures = canvasControl.GraphicsList.SelectedObjects.ToList();

      bool isSelectedFigures = preselectedFigures.Any();
      deleteMenu.Visible = isSelectedFigures;
      duplicateMenu.Visible = isSelectedFigures;
      figureMenuSeparator.Visible = isSelectedFigures;

      for (int i = figureContextMenu.Items.Count - 1; i >= 0; i--)
      {
        ToolStripItem item = figureContextMenu.Items[i];

        if (item.Tag == _figureMarker)
          figureContextMenu.Items.Remove(item);
      }

      for (int i = 0; i < objectsBehindCursor.Count; i++)
      {
        CanvasObject canvasObject = objectsBehindCursor[i];
        var menuItem = new ToolStripMenuItem
        {
          Text = string.Format("{0} {1}", canvasObject.GetType().Name, i + 1),
          Tag = _figureMarker
        };

        CanvasObject currentlyHighlightedObject = canvasObject;
        CanvasObject selectedObject = null;

        menuItem.Click += (sender, args) =>
        {
          canvasControl.GraphicsList.DeselectAll();
          currentlyHighlightedObject.IsSelected = true;
          selectedObject = currentlyHighlightedObject;
          canvasControl.RefreshCanvas();
          ShowPropertiesDialog();
        };

        menuItem.MouseEnter += (sender, args) =>
        {
          canvasControl.GraphicsList.DeselectAll();
          currentlyHighlightedObject.IsSelected = true;
          canvasControl.RefreshCanvas();
        };

        menuItem.MouseLeave += (sender, args) =>
        {
          canvasControl.GraphicsList.DeselectAll();

          if (selectedObject != null)
          {
            //figure was selected by click on selector menu
            selectedObject.IsSelected = true;
          }
          else
          {
            //select all figures that were selected before context menu was shown
            foreach (CanvasObject preselectedFigure in preselectedFigures)
            {
              preselectedFigure.IsSelected = true;
            }
          }

          canvasControl.RefreshCanvas();
        };

        figureContextMenu.Items.Insert(i, menuItem);
      }
    }

    private void SetActiveToolByButton(RadioButton btn)
    {
      if (btn == null)
        return;

      //foreach (RadioButton button in _buttonsToToolsMap.Keys)
      //{
      //  button.Checked = false;
      //}

      btn.Checked = true;
      ActiveTool = _buttonsToToolsMap[btn];
    }

    private void ShowPropertiesDialog()
    {
      List<CanvasObject> selectedObjects = canvasControl.GraphicsList.SelectedObjects.ToList();

      if (!selectedObjects.Any())
        return;

      _propertiesForm.SetViewModel(new PropertiesFormViewModel(selectedObjects, _animator));

      if (!_propertiesForm.Visible)
      {
        _propertiesForm.Location = GetPropertiesFormLocation(selectedObjects.GetGroupBoundingBox());
        _propertiesForm.Show(this);
      }
    }

    private void HidePropertiesDialog()
    {
      // NOTE: do not forget set null to owner, otherwise previous app will be activated!!! 
      // There is strange bug in Winforms
      // Some links with similar behavior
      // http://stackoverflow.com/questions/3369630/my-application-loses-focus-when-a-window-is-closed
      // http://www.neolisk.com/techblog/netwinforms-applicationlosesfocuswhenawindowisclosed
      _propertiesForm.Owner = null; //NOTE: IT'S NECESSARY TO PREVENT FOCUS LOSS BY THE APPLICATION!
      _propertiesForm.Hide();
      _propertiesForm.SetViewModel(null);
    }

    private Point GetPropertiesFormLocation(Rectangle clientBoundingBox)
    {
      //TODO: think how to unify this algorithm
      const int offset = 10;
      Rectangle screenBoundingBox = RectangleToScreen(clientBoundingBox);
      Rectangle screenSize = Screen.FromPoint(screenBoundingBox.Location).WorkingArea;

      int x = screenBoundingBox.Right + offset;
      int y = screenBoundingBox.Top - _propertiesForm.Height - offset;

      if (y < screenSize.Top)
        y = screenSize.Top;

      if (y > screenSize.Bottom - screenBoundingBox.Height)
        y = screenSize.Bottom - screenBoundingBox.Height;

      if (x + screenBoundingBox.Width > screenSize.Right)
        x = screenBoundingBox.X - _propertiesForm.Width - offset;

      if (x < screenSize.Left)
        x = screenSize.Left;

      return new Point(x, y);
    }

    private void Cancel()
    {
      if (_propertiesForm.Visible)
      {
        HidePropertiesDialog();
        //TODO reset current state (to release drag state in pointer tool)
        canvasControl.CancelSelection();
        return;
      }

      DialogResult = DialogResult.Cancel;
      Close();
    }

    private void ResetTool()
    {
      SetActiveToolByButton(pointerToolButton);
    }

    private void AlignToolbars()
    {
      const int offset = 6;
      Rectangle cropRect = canvasControl.Crop.Rectangle;
      Rectangle screen = canvasControl.Crop.GetCurrentScreen(canvasControl.Screens, VertexType.Center);

      cropRect.Intersect(screen);

      toolsPanel.FlowDirection = FlowDirection.TopDown;

      // vertical layout
      toolsPanel.Top = cropRect.Bottom - toolsPanel.Height - offset;
      toolsPanel.Left = cropRect.Right + offset;
      bool toolsFit = screen.Contains(new Rectangle(toolsPanel.Location, toolsPanel.Size));
      AlignToolbarsImpl(offset, toolsFit, cropRect, screen);

      var newToolsRect = new Rectangle(toolsPanel.Location, toolsPanel.Size);
      var newActionsRect = new Rectangle(actionsPanel.Location, actionsPanel.Size);

      //if intersects then align horizontally
      //TODO refactor this. ugly code.
      if (newActionsRect.IntersectsWith(newToolsRect))
        AlignToolbarsImpl(offset, false, cropRect, screen);
    }

    private void AlignToolbarsImpl(int offset, bool toolsFit, Rectangle cropRect, Rectangle screen)
    {
      int verticalPanelHeight = actionsPanel.Height + offset;

      if (!toolsFit)
      {
        //doesnt fit vertically 
        toolsPanel.FlowDirection = FlowDirection.LeftToRight;
        verticalPanelHeight += toolsPanel.Height;
        toolsPanel.Left = cropRect.Right - toolsPanel.Width - offset;
      }

      // horizontal layout
      actionsPanel.Left = cropRect.Right - actionsPanel.Width - offset;

      //at the bottom
      if (verticalPanelHeight + cropRect.Bottom <= screen.Bottom)
      {
        if (!toolsFit)
        {
          toolsPanel.Top = cropRect.Bottom + offset;
          actionsPanel.Top = toolsPanel.Bottom;
        }
        else
        {
          actionsPanel.Top = cropRect.Bottom + offset;
        }
      }
      //try to fit at the top
      else if (cropRect.Top - verticalPanelHeight >= screen.Top)
      {
        if (!toolsFit)
        {
          toolsPanel.Top = cropRect.Top - offset - toolsPanel.Height;
          actionsPanel.Top = toolsPanel.Top - actionsPanel.Height;
        }
        else
        {
          actionsPanel.Top = cropRect.Top - offset - actionsPanel.Height;
        }
      }
      //doesn't fit anywhere. just put it inside crop at the bottom
      else
      {
        actionsPanel.Top = cropRect.Bottom - offset - actionsPanel.Height;
        if (!toolsFit)
        {
          toolsPanel.Top = actionsPanel.Top - actionsPanel.Height;
        }
      }

      toolsPanel.Location = RectangleUtils.FitControlToRectangle(toolsPanel.Size, screen, toolsPanel.Location);
      actionsPanel.Location = RectangleUtils.FitControlToRectangle(actionsPanel.Size, screen, actionsPanel.Location);
    }

    private void ShowToolbars(bool showToolbars)
    {
      toolsPanel.Visible = showToolbars;
      actionsPanel.Visible = showToolbars;
    }

    private void UpdatePropertiesDialogVisibility()
    {
      if (canvasControl.GraphicsList.SelectedObjects.Any())
      {
        ShowPropertiesDialog();
      }
      else
      {
        HidePropertiesDialog();
      }
    }

    private void UploadAndClose()
    {
      CaptureResult = canvasControl.CaptureImage();

      if (CaptureResult.Image != null)
      {
        PlayShotSound();
        DialogResult = DialogResult.OK;
      }
      else
      {
        DialogResult = DialogResult.Abort;
      }

      Close();
    }

    #region Event Handlers

    protected override void OnFormClosing(FormClosingEventArgs e)
    {
      _propertiesForm.Close();
      base.OnFormClosing(e);
    }

    protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
    {
      if (_isTextEditState)
        return base.ProcessCmdKey(ref msg, keyData);

      var keyEventArgs = new KeyEventArgs(keyData);

      if (_canvasHotKeyService.ProcessKey(keyEventArgs))
        return true;

      ActiveTool.OnKeyDown(keyEventArgs);
      return base.ProcessCmdKey(ref msg, keyData);
    }

    private void OnFormLoad(object sender, EventArgs e)
    {
      Icon = Resources.applicationIcon;
      Text = string.Format(Resources.CaptureForm_Title, Application.ProductName);

      var theme = new EditorTheme();

      _textTool = new TextTool(canvasControl, theme.TextSettings, theme.FigureColorSchemes, _changeToolsSection, _resetToolSection, AppCursors.TextToolCursor);

      var pointerTool = new PointerTool(canvasControl, canvasControl, _changeToolsSection, _pointerSection);
      var frameTool = new RectangleTool(canvasControl, theme.FrameSettings, _changeToolsSection, _resetToolSection, AppCursors.FrameToolCursor);
      var rectangleTool = new RectangleTool(canvasControl, theme.RectangleSettings, _changeToolsSection, _resetToolSection, AppCursors.RectangleToolCursor);
      var ellipseTool = new EllipseTool(canvasControl, theme.EllipseSettings, _changeToolsSection, _resetToolSection, AppCursors.EllipseToolCursor);
      var arrowTool = new ArrowTool(canvasControl, theme.ArrowSettings, _changeToolsSection, _resetToolSection, AppCursors.ArrowToolCursor);
      var lineTool = new ArrowTool(canvasControl, theme.LineSettings, _changeToolsSection, _resetToolSection, AppCursors.LineToolCursor);

      _buttonsToToolsMap.Add(pointerToolButton, pointerTool);
      _buttonsToToolsMap.Add(frameToolButton, frameTool);
      _buttonsToToolsMap.Add(rectangleToolButton, rectangleTool);
      _buttonsToToolsMap.Add(ellipseToolButton, ellipseTool);
      _buttonsToToolsMap.Add(arrowToolButton, arrowTool);
      _buttonsToToolsMap.Add(lineToolButton, lineTool);
      _buttonsToToolsMap.Add(textToolButton, _textTool);

      //sets only once in the beginning. we don't need crop tool afterwards
      ActiveTool = new CropTool(canvasControl, new OpenWindowsService(canvasControl, Handle), _createCropSection, _changeToolsSection, AppCursors.CropToolCursor);

      _propertiesForm = new PropertiesForm(canvasControl, theme, _propHotkeyService);
      _propertiesForm.FormClosing += OnPropertiesFormClosing;
      _propertiesForm.ReplaceWithTextRequest += OnReplaceWithTextRequest;
      toolsPanel.Visible = false;
      actionsPanel.Visible = false;

      //_animator.StartIntAnimation(canvasControl.Crop, c=>c.Alpha, 120, 100);
    }

    private void OnReplaceWithTextRequest(object sender, EventArgs eventArgs)
    {
      //TODO in multi select exception will occure
      var rectangle = (CanvasRectangle)canvasControl.GraphicsList.SelectedObjects.Single();
      canvasControl.GraphicsList.RemoveSelection();

      HidePropertiesDialog();
      _textTool.AddTextToGraphicList(rectangle);
    }

    private void OnToolbarButtonClick(object sender, EventArgs e)
    {
      SetActiveToolByButton(sender as RadioButton);
    }

    private void OnCopyClick(object sender, EventArgs e)
    {
      CaptureResult captureResult = canvasControl.CaptureImage();

      if (captureResult.Image != null)
      {
        _clipboardService.SetImage(captureResult.Image);
        PlayShotSound();
        _notificationService.ShowInfo(Resources.Notifications_CopyTitle, Resources.Notifications_CopyBody);
      }

      Close();
    }

    private void OnSaveClick(object sender, EventArgs e)
    {
      var saveShotDialog = new SaveShotDialog(_appConfigurationSection, _isInstantShot ? ShotType.InstantShot : ShotType.ShotAndEdit);
      saveShotDialog.ImageFormats = new[]
      {
        ImageFormat.Png,
        ImageFormat.Jpeg,
        ImageFormat.Bmp
      };

      if (saveShotDialog.ShowDialog() != DialogResult.OK)
        return;

      CaptureResult captureResult = canvasControl.CaptureImage();
      string fileName = saveShotDialog.FileName;

      if (captureResult.Image != null)
      {
        captureResult.Image.SafeSave(fileName, saveShotDialog.SelectedImageFormat);
        _notificationService.ShowInfo(Resources.Notifications_SaveTitle, string.Format(Resources.Notifications_SaveBody, fileName),
                                      () => AppHelper.OpenInViewer(fileName));
      }

      Close();
    }

    private void OnUploadClick(object sender, EventArgs e)
    {
      UploadAndClose();
    }

    private void OnCancelClick(object sender, EventArgs e)
    {
      DialogResult = DialogResult.Cancel;
      Close();
    }

    private void OnDeleteFigureClick(object sender, EventArgs e)
    {
      canvasControl.DeleteSelection();
      UpdatePropertiesDialogVisibility();
    }

    private void OnDuplicateFigureClick(object sender, EventArgs e)
    {
      canvasControl.DuplicateSelection();
      UpdatePropertiesDialogVisibility();
    }

    private void OnCanvasMouseDown(object sender, MouseEventArgs e)
    {
      _isMouseDown = true;

      if (e.Button == MouseButtons.Left)
      {
        ActiveTool.OnMouseDown(e);
      }
      else if (e.Button == MouseButtons.Right)
      {
        if (canvasControl.Crop.IsSelectionState)
        {
          Cancel();
          return;
        }

        HidePropertiesDialog();

        List<CanvasObject> objectsBehindCursor = canvasControl.GetObjectsAtPoint(e.Location).ToList();

        if (objectsBehindCursor.Any())
        {
          FillFiguresContextMenu(objectsBehindCursor);
          figureContextMenu.Show(this, e.Location);
        }
        else
        {
          canvasControl.GraphicsList.DeselectAll();
          canvasControl.RefreshCanvas();
          mainContextMenu.Show(this, e.Location);
        }
      }
    }

    private void OnCanvasMouseMove(object sender, MouseEventArgs e)
    {
      if (_isMouseDown)
      {
        ShowToolbars(false);
      }

      if (e.Button == MouseButtons.Left || e.Button == MouseButtons.None)
        ActiveTool.OnMouseMove(e);
      else
        //TODO why this logic
        canvasControl.Cursor = AppCursors.Default;
    }

    private void OnToggleFullscreenClicked(object sender, EventArgs e)
    {
      if (canvasControl.Crop.IsSelectionState)
        return;

      if (_previousCropRectangle != null)
      {
        //part of the screen
        canvasControl.Crop.Rectangle = _previousCropRectangle.Value;
        _previousCropRectangle = null;
      }
      else
      {
        //fullscreen
        _previousCropRectangle = canvasControl.Crop.Rectangle;
        //TODO too complicated. Crop already has all screens. Move this logic to crop
        canvasControl.Crop.Rectangle =
          canvasControl.RectangleToClient(Screen.FromRectangle(canvasControl.RectangleToScreen(canvasControl.Crop.Rectangle)).Bounds);
      }

      canvasControl.RefreshCanvas();
      AlignToolbars();
    }

    private void OnSelectAllClick(object sender, EventArgs e)
    {
      canvasControl.SelectAll();
      UpdatePropertiesDialogVisibility();
    }

    private void StartEditSelectedCanvasText()
    {
      Focus();
      CanvasText text = canvasControl.GraphicsList.SelectedObjects.OfType<CanvasText>().FirstOrDefault();
      if (text != null)
        canvasControl.BeginTextEdit(text);
    }

    private void OnDeleteAllClick(object sender, EventArgs e)
    {
      canvasControl.GraphicsList.Clear();
      canvasControl.RefreshCanvas();
    }

    private void OnCanvasMouseUp(object sender, MouseEventArgs e)
    {
      _isMouseDown = false;

      if (e.Button == MouseButtons.Left)
      {
        ActiveTool.OnMouseUp(e);
        SetActiveToolByButton(pointerToolButton);
        UpdatePropertiesDialogVisibility();
      }

      if (canvasControl.Crop.IsSelectionState)
        return;

      if (_isInstantShot)
      {
        UploadAndClose();
      }
      else
      {
        AlignToolbars();
        ShowToolbars(true);
      }
    }

    private void OnPropertiesFormClosing(object sender, FormClosingEventArgs cancelEventArgs)
    {
      if (cancelEventArgs.CloseReason == CloseReason.UserClosing)
      {
        cancelEventArgs.Cancel = true;
        HidePropertiesDialog();
      }
    }

    private void OnCanvasKeyUp(object sender, KeyEventArgs e)
    {
      ActiveTool.OnKeyUp(e);
    }

    private void OnTextEditStart(object sender, EventArgs e)
    {
      //TODO: refactor this, maybe just turn off hotkey service or turn off all sections
      _isTextEditState = true;
    }

    private void OnTextEditEnd(object sender, TextEditEndEventArgs args)
    {
      _isTextEditState = false;
      UpdatePropertiesDialogVisibility();
    }

    private void OnToolbarPanelPaint(object sender, PaintEventArgs e)
    {
      var control = sender as Control;

      if (control == null)
        return;

      const int penWidth = 1;

      Rectangle rect = control.ClientRectangle;

      using (var borderPen = new Pen(Color.FromArgb(73, 73, 73), penWidth))
      {
        e.Graphics.DrawRectangle(borderPen, rect.X, rect.Y, rect.Width - penWidth, rect.Height - penWidth);
      }
    }

    #endregion
  }
}